package com.jrx.anytxn.transaction.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.TxnBizException;
import com.jrx.anytxn.common.exception.TxnException;
import com.jrx.anytxn.common.uitl.BeanMapping;
import com.jrx.anytxn.customer.entity.CmCustomerSecondLevel;
import com.jrx.anytxn.customer.mapper.ext.ExtCmCustomerSecondLevelMapper;
import com.jrx.anytxn.i18n.response.TxnPage;
import com.jrx.anytxn.number.exception.SegmentException;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.entity.PrOrganizationTable;
import com.jrx.anytxn.param.service.system.IOrganizationTableService;
import com.jrx.anytxn.ribbon.config.GrayVersionConfig;
import com.jrx.anytxn.transaction.bean.DealMistakeBean;
import com.jrx.anytxn.transaction.bean.PaymentSaveBean;
import com.jrx.anytxn.transaction.bean.PayoffProveMessage;
import com.jrx.anytxn.transaction.constant.TransBizConstant;
import com.jrx.anytxn.transaction.dto.mistakeLog.MistakeLogRes;
import com.jrx.anytxn.transaction.entity.*;
import com.jrx.anytxn.transaction.handler.IPaymentHandler;
import com.jrx.anytxn.transaction.mapper.ext.*;
import com.jrx.anytxn.transaction.service.IDealPaymentService;
import com.jrx.anytxn.transaction.service.IMistakeService;
import com.jrx.anytxn.transaction.service.IThirdPartyPaymentService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @program: anytxn-cf-transaction
 * @description: 差错处理操作类
 * @author: xiaoyu.jing
 * @date: 2019-10-24 09:50
 **/
@Service
public class MistakeServiceImpl implements IMistakeService {

    private static final Logger logger = LoggerFactory.getLogger(MistakeServiceImpl.class);

    @Autowired
    private ISegmentService segmentService;
    @Resource
    private ExtTlPaymentLogMapper extTlPaymentLogMapper;
    @Autowired
    private IPaymentHandler paymentHandler;
    @Resource
    private ExtTlMistakeLogMapper extTlMistakeLogMapper;
    @Autowired
    private IOrganizationTableService organizationTableService;
    @Resource
    private ExtTlWaivePaymentLogMapper extTlWaivePaymentLogMapper;
    @Resource
    private ExtTlLoanStagingMappingMapper extTlLoanStagingMappingMapper;
    @Autowired
    private IDealPaymentService dealPaymentService;
    @Resource
    private ExtTlThirdPartyPaymentMapper extTlThirdPartyPaymentMapper;
    @Autowired
    private IThirdPartyPaymentService thirdPartyPaymentService;
    @Autowired
    private GrayVersionConfig grayVersionConfig;
    @Resource
    private ExtCmCustomerSecondLevelMapper extCmCustomerSecondLevelMapper;
    @Resource
    private ExtAmLoanAccountInfoMapper extAmLoanAccountInfoMapper;
    @Resource
    private ExtAmLoanMainInfoMapper extAmLoanMainInfoMapper;


    /**
     * 处理差错记录
     *
     * @param bean
     * @throws Exception
     */
    @Override
    public void dealMistakeRecord(DealMistakeBean bean) throws Exception {
        Long recordId = bean.getId();
        String misType = bean.getMisType();
        String orgiSeqNo = bean.getOrgiSeqNo();
        String customerId = bean.getCustomerId();
        String tenantId = bean.getTenantId();
        String orgId = bean.getOrganizationId();
        PrOrganizationTable organization =
                organizationTableService.findByOrId(orgId, tenantId);
        Date bussinessDate = organization.getNextProcessingDate();
        if (TransBizConstant.MIS_TYPE_0.equals(misType)) {
            this.dealLoanMistakeRecord(recordId, orgiSeqNo, customerId, tenantId, bussinessDate);
        } else if (TransBizConstant.MIS_TYPE_3.equals(misType)) {
            this.dealWaiveRepayMistakeRecord(recordId, orgiSeqNo, customerId, tenantId, bussinessDate);
        } else if (TransBizConstant.MIS_TYPE_2.equals(misType)) {
            //orgiSeqNo 账单分期订单号
            this.dealLoanStagingMistakeRecord(recordId, orgiSeqNo, customerId, tenantId, bussinessDate);
        } else if (TransBizConstant.MIS_TYPE_4.equals(misType)) {
            this.dealThirdRepayMistakeRecord(recordId, orgiSeqNo, customerId, tenantId, bussinessDate);
        } else if (TransBizConstant.MIS_TYPE_1.equals(misType)) {
            this.dealRepayMistakeRecord(recordId, orgiSeqNo, customerId, tenantId, bussinessDate);
        } else if (TransBizConstant.MIS_TYPE_5.equals(misType)) {
            this.dealMqMistakeRecord(recordId, orgiSeqNo, customerId, tenantId, bussinessDate);
        } else if (TransBizConstant.MIS_TYPE_6.equals(misType)) {
            this.dealWaiveMqMistakeRecord(recordId, orgiSeqNo, customerId, tenantId, bussinessDate);
        } else if (TransBizConstant.MIS_TYPE_7.equals(misType)) {
            this.dealFileRepayMistakeRecord(recordId, orgiSeqNo, customerId, tenantId, bussinessDate);
        } else if (TransBizConstant.MIS_TYPE_8.equals(misType)) {
            this.dealPayoffProveMqRecord(recordId, orgiSeqNo, customerId, tenantId, bussinessDate);
        }
    }

    @Override
    public TxnPage<MistakeLogRes> findMistakeLogByTenId(Integer pageNum, Integer pageSize, String tenantId) throws TxnBizException {
        Page<TlMistakeLog> page = PageHelper.startPage(pageNum, pageSize);
        List<TlMistakeLog> mistakeLogList = extTlMistakeLogMapper.selectByTenantId(tenantId);
        if (mistakeLogList.isEmpty()) {
            logger.error("查询差错流水记录列表为空");
            throw new TxnBizException(TxnRespCode.NO_DATA.getCode(), TxnRespCode.NO_DATA.getUserTips());
        }
        List<MistakeLogRes> res = BeanMapping.copyList(mistakeLogList, MistakeLogRes.class);
        return new TxnPage<>(pageNum, pageSize, page.getTotal(), res);
    }

    /**
     * 处理放款差错
     *
     * @param recordId
     * @param orgiSeqNo
     * @param customerId
     * @param tenantId
     * @throws Exception
     */
    private void dealLoanMistakeRecord(Long recordId, String orgiSeqNo, String customerId, String tenantId, Date bussinessDate) {
    }

    /**
     * 处理还款款差错
     *
     * @param recordId
     * @param orgiSeqNo
     * @param customerId
     * @param tenantId
     * @throws Exception
     */
    private void dealRepayMistakeRecord(Long recordId, String orgiSeqNo, String customerId, String tenantId, Date bussinessDate) throws Exception {
        TlPaymentLog log = extTlPaymentLogMapper.selectPaymentStatusByPaymentSeqNo(orgiSeqNo, customerId, tenantId);
        paymentHandler.dealAllocation(log, bussinessDate);

        extTlMistakeLogMapper.updateMistake(recordId, customerId, tenantId, bussinessDate);

        // mq发送还款流水给出资方
        try {
            paymentHandler.sendMqPaymentLog(TransBizConstant.MQ_INVESTOR_PAYMENT_TOPIC + grayVersionConfig.getCurrentVersion(), log);
        } catch (Exception e) {
            logger.error("mq发送还款流水给出资方异常：{}", e);
            TlMistakeLog mistakeLog = this.buildMistakeLog(log, bussinessDate, TransBizConstant.MIS_TYPE_5);
            extTlMistakeLogMapper.insertSelective(mistakeLog);
            return;
        }

        //更新流水表状态
        TlPaymentLog updateLog = new TlPaymentLog();
        updateLog.setId(log.getId());
        updateLog.setCustomerId(log.getCustomerId());
        updateLog.setTenantId(log.getTenantId());
        updateLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_S);
        extTlPaymentLogMapper.updateByIdAndCustomerIdAndTenantId(updateLog);
    }

    /**
     * 处理账单分期差错
     *
     * @param recordId
     * @param orgiSeqNo
     * @param customerId
     * @param tenantId
     * @param bussinessDate
     * @throws TxnException
     */
    private void dealLoanStagingMistakeRecord(Long recordId, String orgiSeqNo, String customerId, String tenantId, Date bussinessDate) throws TxnException {

        List<TlLoanStagingMapping> tlLoanStagList = extTlLoanStagingMappingMapper.selectByStagingLoanIdByMis(orgiSeqNo, tenantId);
        dealPaymentService.dealLoanStaging(tlLoanStagList, bussinessDate);
        //更新账单分期关联表
        extTlLoanStagingMappingMapper.updateByStagingLoanId(tenantId, customerId, tlLoanStagList.get(0).getStagingLoanId(), TransBizConstant.LOAN_STAGING_SUM_STATUS_S);
        //更新差错记录表
        extTlMistakeLogMapper.updateMistake(recordId, customerId, tenantId, bussinessDate);

    }

    /**
     * 处理贴息还款差错
     *
     * @param recordId
     * @param orgiSeqNo
     * @param customerId
     * @param tenantId
     * @param bussinessDate
     * @throws TxnException
     */
    private void dealWaiveRepayMistakeRecord(Long recordId, String orgiSeqNo, String customerId, String tenantId, Date bussinessDate) throws TxnException {
        TlWaivePaymentLog log = extTlWaivePaymentLogMapper.selectPaymentStatusByPaymentSeqNo(orgiSeqNo, customerId, tenantId);
        paymentHandler.dealWaiveAllocation(log, bussinessDate);

        extTlMistakeLogMapper.updateMistake(recordId, customerId, tenantId, bussinessDate);

        // mq发送贴息还款流水给出资方
        try {
            paymentHandler.sendMqPaymentLog(TransBizConstant.MQ_INVESTOR_WAIVE_PAYMENT_TOPIC + grayVersionConfig.getCurrentVersion(), log);
        } catch (Exception e) {
            logger.error("mq发送贴息还款流水给出资方异常：{}", e);
            TlMistakeLog mistakeLog = this.buildMistakeLog(log, bussinessDate, TransBizConstant.MIS_TYPE_6);
            extTlMistakeLogMapper.insertSelective(mistakeLog);
            return;
        }

        //更新流水表状态
        TlWaivePaymentLog updateLog = new TlWaivePaymentLog();
        updateLog.setId(log.getId());
        updateLog.setCustomerId(log.getCustomerId());
        updateLog.setTenantId(log.getTenantId());
        updateLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_S);
        extTlWaivePaymentLogMapper.updateByIdAndCustomerIdAndTenantId(updateLog);
    }

    /**
     * 三方还款差错
     *
     * @param recordId
     * @param orgiSeqNo
     * @param customerId
     * @param tenantId
     * @param bussinessDate
     * @throws TxnException
     */
    private void dealThirdRepayMistakeRecord(Long recordId, String orgiSeqNo, String customerId, String tenantId, Date bussinessDate) throws Exception {
        TlThirdPartyPayment log = extTlThirdPartyPaymentMapper.selectPaymentStatusBySeqNo(orgiSeqNo, customerId, tenantId);
        thirdPartyPaymentService.dealAllocationByThirdParty(log, bussinessDate);
        //更新三方流水表状态
        TlThirdPartyPayment updateLog = new TlThirdPartyPayment();
        updateLog.setId(log.getId());
        updateLog.setCustomerId(log.getCustomerId());
        updateLog.setTenantId(log.getTenantId());
        updateLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_S);
        extTlThirdPartyPaymentMapper.updateByIdAndCustomerIdAndTenantId(updateLog);
        extTlMistakeLogMapper.updateMistake(recordId, customerId, tenantId, bussinessDate);
    }

    /**
     * 根据还款流水生成差错对象
     *
     * @param tlPaymentLog
     * @param bussinessDate
     * @param misType
     * @return
     */
    @Override
    public TlMistakeLog buildMistakeLog(TlPaymentLog tlPaymentLog, Date bussinessDate, String misType) throws TxnBizException {
        TlMistakeLog log = new TlMistakeLog();
        try {
            log.setId(segmentService.getId(TransBizConstant.TL_MISTAKE_LOG_ID));
        } catch (SegmentException e) {
            logger.error("主键生成错误", e);
            throw new TxnBizException(TxnRespCode.ERROR.getUserTips());
        }
        log.setTenantId(tlPaymentLog.getTenantId());
        log.setCustomerId(tlPaymentLog.getCustomerId());
        log.setOrganizationId(tlPaymentLog.getOrganizationId());
        log.setOrgiSeqNo(tlPaymentLog.getSeqNo());
        log.setMisType(misType);
        log.setMisStatus(TransBizConstant.MIS_STATUS_0);
        log.setMisAddDate(bussinessDate);
        log.setMisDealCount(0);
        log.setRecordVersionNumber(TransBizConstant.INIT_RECORD_VERSION_NUMBER);
        log.setUpdateBy(TransBizConstant.SYS_OPRATE);
        return log;
    }

    @Override
    public TlMistakeLog buildMistakeLog(List<TlLoanStagingMapping> tlLoanStagingMappingList, Date bussinessDate) throws TxnBizException {
        TlMistakeLog log = new TlMistakeLog();
        try {
            log.setId(segmentService.getId(TransBizConstant.TL_MISTAKE_LOG_ID));
        } catch (SegmentException e) {
            logger.error("主键生成错误", e);
            throw new TxnBizException(TxnRespCode.ERROR.getUserTips());
        }
        log.setTenantId(tlLoanStagingMappingList.get(0).getTenantId());
        log.setCustomerId(tlLoanStagingMappingList.get(0).getCustomerId());
        log.setOrganizationId(tlLoanStagingMappingList.get(0).getOrganizationId());
        log.setOrgiSeqNo(tlLoanStagingMappingList.get(0).getStagingLoanId());//记录账单分期订单号
        log.setMisType(TransBizConstant.MIS_TYPE_2);
        log.setMisStatus(TransBizConstant.MIS_STATUS_0);
        log.setMisAddDate(bussinessDate);
        log.setMisDealCount(0);
        log.setRecordVersionNumber(TransBizConstant.INIT_RECORD_VERSION_NUMBER);
        log.setUpdateBy(TransBizConstant.SYS_OPRATE);
        return log;
    }

    /**
     * 根据还款流水生成差错对象
     *
     * @param tlWaivePaymentLog
     * @param bussinessDate
     * @param misType
     * @return
     */
    @Override
    public TlMistakeLog buildMistakeLog(TlWaivePaymentLog tlWaivePaymentLog, Date bussinessDate, String misType) throws TxnBizException {
        TlMistakeLog log = new TlMistakeLog();
        try {
            log.setId(segmentService.getId(TransBizConstant.TL_MISTAKE_LOG_ID));
        } catch (SegmentException e) {
            logger.error("主键生成错误", e);
            throw new TxnBizException(TxnRespCode.ERROR.getUserTips());
        }
        log.setTenantId(tlWaivePaymentLog.getTenantId());
        log.setCustomerId(tlWaivePaymentLog.getCustomerId());
        log.setOrganizationId(tlWaivePaymentLog.getOrganizationId());
        log.setOrgiSeqNo(tlWaivePaymentLog.getSeqNo());
        log.setMisType(misType);
        log.setMisStatus(TransBizConstant.MIS_STATUS_0);
        log.setMisAddDate(bussinessDate);
        log.setMisDealCount(0);
        log.setRecordVersionNumber(TransBizConstant.INIT_RECORD_VERSION_NUMBER);
        log.setUpdateBy(TransBizConstant.SYS_OPRATE);
        return log;
    }

    @Override
    public TlMistakeLog buildMistakeLog(TlThirdPartyPayment tlThirdPartyPayment, Date bussinessDate) throws TxnBizException {
        TlMistakeLog log = new TlMistakeLog();
        try {
            log.setId(segmentService.getId(TransBizConstant.TL_MISTAKE_LOG_ID));
        } catch (SegmentException e) {
            logger.error("主键生成错误", e);
            throw new TxnBizException(TxnRespCode.ERROR.getUserTips());
        }
        log.setTenantId(tlThirdPartyPayment.getTenantId());
        log.setCustomerId(tlThirdPartyPayment.getCustomerId());
        log.setOrganizationId(tlThirdPartyPayment.getOrganizationId());
        log.setOrgiSeqNo(tlThirdPartyPayment.getSeqNo());
        log.setMisType(TransBizConstant.MIS_TYPE_4);
        log.setMisStatus(TransBizConstant.MIS_STATUS_0);
        log.setMisAddDate(bussinessDate);
        log.setMisDealCount(0);
        log.setRecordVersionNumber(TransBizConstant.INIT_RECORD_VERSION_NUMBER);
        log.setUpdateBy(TransBizConstant.SYS_OPRATE);
        return log;
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void batchInsert(List<TlMistakeLog> tlMistakeLogList) {
        extTlMistakeLogMapper.batchInsert(tlMistakeLogList);
    }

    /**
     * 处理Mq发送差错
     *
     * @param recordId
     * @param orgiSeqNo
     * @param customerId
     * @param tenantId
     * @throws Exception
     */
    private void dealMqMistakeRecord(Long recordId, String orgiSeqNo, String customerId, String tenantId, Date bussinessDate) throws Exception {
        TlPaymentLog log = extTlPaymentLogMapper.selectPaymentStatusByPaymentSeqNo(orgiSeqNo, customerId, tenantId);
        paymentHandler.sendMqPaymentLog(TransBizConstant.MQ_INVESTOR_PAYMENT_TOPIC + grayVersionConfig.getCurrentVersion(), log);
        //更新流水表状态
        TlPaymentLog updateLog = new TlPaymentLog();
        updateLog.setId(log.getId());
        updateLog.setCustomerId(log.getCustomerId());
        updateLog.setTenantId(log.getTenantId());
        updateLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_S);
        extTlPaymentLogMapper.updateByIdAndCustomerIdAndTenantId(updateLog);
        extTlMistakeLogMapper.updateMistake(recordId, customerId, tenantId, bussinessDate);
    }

    /**
     * 处理贴息还款Mq发送差错
     *
     * @param recordId
     * @param orgiSeqNo
     * @param customerId
     * @param tenantId
     * @throws Exception
     */
    private void dealWaiveMqMistakeRecord(Long recordId, String orgiSeqNo, String customerId, String tenantId, Date bussinessDate) throws Exception {
        TlWaivePaymentLog log = extTlWaivePaymentLogMapper.selectPaymentStatusByPaymentSeqNo(orgiSeqNo, customerId, tenantId);
        paymentHandler.sendMqPaymentLog(TransBizConstant.MQ_INVESTOR_WAIVE_PAYMENT_TOPIC + grayVersionConfig.getCurrentVersion(), log);
        //更新流水表状态
        TlPaymentLog updateLog = new TlPaymentLog();
        updateLog.setId(log.getId());
        updateLog.setCustomerId(log.getCustomerId());
        updateLog.setTenantId(log.getTenantId());
        updateLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_S);
        extTlPaymentLogMapper.updateByIdAndCustomerIdAndTenantId(updateLog);
        extTlMistakeLogMapper.updateMistake(recordId, customerId, tenantId, bussinessDate);
    }


    /**
     * 处理结清证明MQ发送异常
     *
     * @param recordId
     * @param orgiSeqNo
     * @param customerId
     * @param tenantId
     * @throws Exception
     */
    private void dealPayoffProveMqRecord(Long recordId, String orgiSeqNo, String customerId, String tenantId, Date bussinessDate) throws Exception {
        TlThirdPartyPayment log = extTlThirdPartyPaymentMapper.selectPaymentStatusBySeqNo(orgiSeqNo, customerId, tenantId);
        String channel = log.getChannel();
        String loanId = log.getLoanId();
        AmLoanMainInfo amLoanMainInfo = extAmLoanMainInfoMapper.selectByLoanId(loanId, customerId, tenantId, channel);
        AmLoanAccountInfo amLoanAccountInfo = extAmLoanAccountInfoMapper.selectByLoanId(loanId, customerId, tenantId);
        PayoffProveMessage message = new PayoffProveMessage();
        message.setChannelNo(channel);
        message.setTenantId(tenantId);
        message.setLoanNo(loanId);
        message.setLoanDate(amLoanMainInfo.getPostingDate());
        message.setPayoffDate(amLoanAccountInfo.getPayoffDate());
        message.setTotalTenor(amLoanMainInfo.getTotalTenor());
        message.setLoanAmount(amLoanMainInfo.getLoanAmount());
        CmCustomerSecondLevel secondLevel = extCmCustomerSecondLevelMapper.selectByCustomerIdAndChannel(customerId, channel, tenantId);
        message.setUserId(secondLevel.getUserId());
        paymentHandler.sendMqPaymentLog(TransBizConstant.MQ_PAYOFF_PROVE_TOPIC + grayVersionConfig.getCurrentVersion(), message);
        extTlMistakeLogMapper.updateMistake(recordId, customerId, tenantId, bussinessDate);
    }

    /**
     * 文件三方还款差错
     *
     * @param recordId
     * @param orgiSeqNo
     * @param customerId
     * @param tenantId
     * @param bussinessDate
     * @throws TxnException
     */
    private void dealFileRepayMistakeRecord(Long recordId, String orgiSeqNo, String customerId, String tenantId, Date bussinessDate) throws Exception {
        TlThirdPartyPayment log = extTlThirdPartyPaymentMapper.selectPaymentStatusBySeqNo(orgiSeqNo, customerId, tenantId);
        thirdPartyPaymentService.dealAndSaveFilePayAllocate(log, bussinessDate);
        //更新三方流水表状态
        TlThirdPartyPayment updateLog = new TlThirdPartyPayment();
        updateLog.setId(log.getId());
        updateLog.setCustomerId(log.getCustomerId());
        updateLog.setTenantId(log.getTenantId());
        updateLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_S);
        extTlThirdPartyPaymentMapper.updateByIdAndCustomerIdAndTenantId(updateLog);
        extTlMistakeLogMapper.updateMistake(recordId, customerId, tenantId, bussinessDate);
        //发送api mq消息 生成结清证明
        try {
            this.dealPayoffProveMqRecord(recordId, orgiSeqNo, customerId, tenantId, bussinessDate);
        } catch (Exception e) {
            logger.error("提前结清证明发送mq异常:", e);
            TlMistakeLog mistakeLog = this.buildMistakeLog(log, bussinessDate);
            mistakeLog.setMisType(TransBizConstant.MIS_TYPE_8);
            extTlMistakeLogMapper.insert(mistakeLog);
        }

    }
}
